package com.corpgovernment.organization.service.budget;

import com.corpgovernment.api.organization.bo.budget.OccupyBudgetRequestBO;
import com.corpgovernment.api.organization.bo.budget.OccupyBudgetResponseBO;
import com.corpgovernment.organization.entity.db.budget.BudgetInfoEntity;
import com.corpgovernment.organization.entity.db.budget.BudgetItemEntity;
import com.corpgovernment.organization.entity.db.budget.BudgetOccupancyEntity;
import com.corpgovernment.organization.mapper.budget.BudgetInfoMapper;
import com.corpgovernment.organization.mapper.budget.BudgetItemMapper;
import com.corpgovernment.organization.mapper.budget.BudgetOccupancyMapper;
import com.corpgovernment.organization.mq.MultiTenantBudgetNotifyProducer;
import com.corpgovernment.organization.util.BudgetAlarmUtil;
import com.corpgovernment.organization.util.PreCheckUtil;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;

@Slf4j
@Service
public class OccupyBudgetService extends BaseBudgetService<OccupyBudgetRequestBO, OccupyBudgetResponseBO> {

    @Resource
    private BudgetOccupancyMapper budgetOccupancyMapper;

    @Resource
    private BudgetItemMapper budgetItemMapper;

    @Resource
    private BudgetInfoMapper budgetInfoMapper;

    @Resource
    private MultiTenantBudgetNotifyProducer multiTenantBudgetNotifyProducer;

    /**
     * 预占预算
     */
    private OccupyBudgetResponseBO occupyBudget(OccupyBudgetRequestBO request) {
        //更新item、总预算
        BudgetInfoEntity budgetInfo = budgetInfoMapper.selectByPrimaryKey(request.getBudgetId());
        PreCheckUtil.checkNotNull(budgetInfo, "预算单号错误，没有查询到预算单配置");
        PreCheckUtil.checkArgument(!budgetInfo.getIsDeleted(), "该预算单已不可用，请检查");
        PreCheckUtil.checkArgument(budgetInfo.getIsActive(), "该预算单已冻结，请检查");
        List<BudgetItemEntity> budgetItems = budgetItemMapper.selectByBudgetId(request.getBudgetId());
        Set<String> productSet = request.getProductFeeOccupy().keySet();
        Set<String> productOccupancySet = Sets.newHashSet();
        BigDecimal feeTotal = new BigDecimal(0);
        for (BudgetItemEntity budgetItem : budgetItems) {
            BigDecimal fee = new BigDecimal(0);
            BigDecimal surplus = BudgetAlarmUtil.calSurplus(budgetItem.getAmount(), budgetItem.getAmountUsed(), budgetItem.getAmountOccupy());
            for (String product : budgetItem.getType().split("/")) {
                if (productSet.contains(product)) {
                    fee = fee.add(request.getProductFeeOccupy().get(product));
                    productOccupancySet.add(product);
                }
            }
            PreCheckUtil.checkArgument(surplus.compareTo(fee) >= 0, String.format("预算项[%s]余额不足，预占失败", budgetItem.getTypeDesc()));
            budgetItem.setAmountOccupy(budgetItem.getAmountOccupy().add(fee));
            feeTotal = feeTotal.add(fee);
        }
        BigDecimal surplusTotal = BudgetAlarmUtil.calSurplus(budgetInfo.getAmount(), budgetInfo.getAmountUsed(), budgetInfo.getAmountOccupy());
        PreCheckUtil.checkArgument(surplusTotal.compareTo(feeTotal) >= 0, "预算总余额不足，预占失败");
        budgetInfo.setAmountOccupy(budgetInfo.getAmountOccupy().add(feeTotal));
        budgetInfoMapper.updateSelective(budgetInfo);
        budgetItemMapper.updateBatchSelective(budgetItems);
        //更新occupancy
        request.getProductFeeOccupy().keySet().forEach(p -> {
            if (productOccupancySet.contains(p)) {
                BudgetOccupancyEntity budgetOccupancy = budgetOccupancyMapper.selectByBudgetIdAndProductTypeAndApplyNo(request.getBudgetId(), request.getApplyNo(), p);
                if (budgetOccupancy == null) {
                    budgetOccupancy = new BudgetOccupancyEntity();
                    budgetOccupancy.setBudgetId(request.getBudgetId());
                    budgetOccupancy.setApplyNo(request.getApplyNo());
                    budgetOccupancy.setProductType(p);
                    budgetOccupancy.setAmountOccupy(request.getProductFeeOccupy().get(p));
                    budgetOccupancy.setAmountUsed(new BigDecimal(0));
                    budgetOccupancyMapper.insertSelective(budgetOccupancy);
                } else {
                    budgetOccupancy.setAmountOccupy(budgetOccupancy.getAmountOccupy().add(request.getProductFeeOccupy().get(p)));
                    budgetOccupancyMapper.updateSelective(budgetOccupancy);
                }
            }
        });
        //发送预算阀值告警消息
        multiTenantBudgetNotifyProducer.sendBudgetNotifyMsg(request.getBudgetId());
        return OccupyBudgetResponseBO.success();
    }

    @Override
    @Transactional
    public OccupyBudgetResponseBO doOperation(OccupyBudgetRequestBO request) {
        return occupyBudget(request);
    }
}